if ( !shadow_remove_all_write_access(d, gpfn, gmfn) )
{
- FSH_LOG("%s: couldn't find/remove all write accesses, gpfn=%p gmfn=%p\n",
+ FSH_LOG("%s: couldn't find/remove all write accesses, gpfn=%p gmfn=%p",
__func__, gpfn, gmfn);
+#if 1 || defined(LIVE_DANGEROUSLY)
+ set_bit(_PGC_page_table, &page->count_info);
+ return 1;
+#endif
return 0;
+
}
// To convert this page to use as a page table, the writable count
return smfn;
fail:
- FSH_LOG("promotion of pfn=%p mfn=%p failed! external gnttab refs?\n",
+ FSH_LOG("promotion of pfn=%p mfn=%p failed! external gnttab refs?",
gpfn, gmfn);
free_domheap_page(page);
return 0;
}
unmap_domain_mem(pl1e);
-
- list_add(&spage->list, &d->arch.free_shadow_frames);
- perfc_incr(free_l1_pages);
}
static void inline
l1_pgentry_t *hl2 = map_domain_mem(smfn << PAGE_SHIFT);
int i, limit;
+ SH_VVLOG("%s: smfn=%p freed\n", __func__, smfn);
+
#ifdef __i386__
if ( shadow_mode_external(d) )
limit = L2_PAGETABLE_ENTRIES;
put_shadow_ref(pl2e[i] >> PAGE_SHIFT);
if ( (PGT_base_page_table == PGT_l2_page_table) &&
- shadow_mode_translate(d) &&
- !shadow_mode_external(d) )
+ shadow_mode_translate(d) && !external )
{
// free the ref to the hl2
//
unsigned long gpfn = __mfn_to_gpfn(d, gmfn);
unsigned long type = page->u.inuse.type_info & PGT_type_mask;
+ SH_VVLOG("%s: free'ing smfn=%p", __func__, smfn);
+
ASSERT( ! IS_INVALID_M2P_ENTRY(gpfn) );
delete_shadow_status(d, gpfn, gmfn, type);
page->tlbflush_timestamp = 0;
page->u.free.cpu_mask = 0;
- if ( type != PGT_l1_shadow )
+ if ( type == PGT_l1_shadow )
+ {
+ list_add(&page->list, &d->arch.free_shadow_frames);
+ perfc_incr(free_l1_pages);
+ }
+ else
free_domheap_page(page);
}
static void free_shadow_pages(struct domain *d)
{
- int i, free = 0;
- struct shadow_status *x, *n;
- struct exec_domain *e;
+ int i;
+ struct shadow_status *x;
+ struct exec_domain *ed;
/*
* WARNING! The shadow page table must not currently be in use!
// second, remove any outstanding refs from ed->arch.shadow_table...
//
- for_each_exec_domain(d, e)
+ for_each_exec_domain(d, ed)
{
- if ( pagetable_val(e->arch.shadow_table) )
+ if ( pagetable_val(ed->arch.shadow_table) )
{
- put_shadow_ref(pagetable_val(e->arch.shadow_table) >> PAGE_SHIFT);
- e->arch.shadow_table = mk_pagetable(0);
+ put_shadow_ref(pagetable_val(ed->arch.shadow_table) >> PAGE_SHIFT);
+ ed->arch.shadow_table = mk_pagetable(0);
+ }
+ }
+
+ // For external shadows, remove the monitor table's refs
+ //
+ if ( shadow_mode_external(d) )
+ {
+ for_each_exec_domain(d, ed)
+ {
+ l2_pgentry_t *mpl2e = ed->arch.monitor_vtable;
+ l2_pgentry_t hl2e = mpl2e[l2_table_offset(LINEAR_PT_VIRT_START)];
+ l2_pgentry_t smfn = mpl2e[l2_table_offset(SH_LINEAR_PT_VIRT_START)];
+ if ( l2_pgentry_val(hl2e) & _PAGE_PRESENT )
+ {
+ put_shadow_ref(l2_pgentry_val(hl2e) >> PAGE_SHIFT);
+ mpl2e[l2_table_offset(LINEAR_PT_VIRT_START)] = mk_l2_pgentry(0);
+ }
+ if ( l2_pgentry_val(smfn) & _PAGE_PRESENT )
+ {
+ put_shadow_ref(l2_pgentry_val(smfn) >> PAGE_SHIFT);
+ mpl2e[l2_table_offset(SH_LINEAR_PT_VIRT_START)] = mk_l2_pgentry(0);
+ }
}
}
// Now, the only refs to shadow pages that are left are from the shadow
- // pages themselves. We can just free them.
+ // pages themselves. We just unpin the pinned pages, and the rest
+ // should automatically disappear.
//
+ // NB: Beware: each explicitly or implicit call to free_shadow_page
+ // can/will result in the hash bucket getting rewritten out from
+ // under us... First, collect the list of pinned pages, then
+ // free them.
+ //
+#define PINNED(_x) (frame_table[_x].u.inuse.type_info & PGT_pinned)
for ( i = 0; i < shadow_ht_buckets; i++ )
{
+ u32 count;
+ unsigned long *mfn_list;
+
/* Skip empty buckets. */
x = &d->arch.shadow_ht[i];
if ( x->gpfn_and_flags == 0 )
continue;
- /* Free the head page. */
- free_shadow_page(x->smfn);
-
- /* Reinitialise the head node. */
- x->gpfn_and_flags = 0;
- x->smfn = 0;
- n = x->next;
- x->next = NULL;
-
- free++;
-
- /* Iterate over non-head nodes. */
- for ( x = n; x != NULL; x = n )
- {
- /* Free the shadow page. */
- free_shadow_page(x->smfn);
-
- /* Re-initialise the chain node. */
- x->gpfn_and_flags = 0;
- x->smfn = 0;
+ count = 0;
+ for ( ; x != NULL; x = x->next )
+ if ( PINNED(x->smfn) )
+ count++;
+ if ( !count )
+ continue;
- /* Add to the free list. */
- n = x->next;
- x->next = d->arch.shadow_ht_free;
- d->arch.shadow_ht_free = x;
+ mfn_list = xmalloc_array(unsigned long, count);
+ count = 0;
+ for ( x = &d->arch.shadow_ht[i]; x != NULL; x = x->next )
+ if ( PINNED(x->smfn) )
+ mfn_list[count++] = x->smfn;
- free++;
+ while ( count )
+ {
+ shadow_unpin(mfn_list[--count]);
}
-
- shadow_audit(d, 0);
+ xfree(mfn_list);
}
+#undef PINNED
+
+ shadow_audit(d, 0);
- SH_LOG("Free shadow table. Freed=%d.", free);
+ SH_LOG("Free shadow table.");
}
void shadow_mode_init(void)
mpl2e[l2_table_offset(RO_MPT_VIRT_START)] =
mk_l2_pgentry(pagetable_val(d->arch.phys_table) | __PAGE_HYPERVISOR);
+ // Don't (yet) have mappings for these...
+ // Don't want to accidentally see the idle_pg_table's linear mapping.
+ //
+ mpl2e[l2_table_offset(LINEAR_PT_VIRT_START)] = mk_l2_pgentry(0);
+ mpl2e[l2_table_offset(SH_LINEAR_PT_VIRT_START)] = mk_l2_pgentry(0);
+
ed->arch.monitor_table = mk_pagetable(mmfn << PAGE_SHIFT);
ed->arch.monitor_vtable = mpl2e;
}
*/
void free_monitor_pagetable(struct exec_domain *ed)
{
- l2_pgentry_t *mpl2e, hl2e;
+ l2_pgentry_t *mpl2e, hl2e, sl2e;
unsigned long mfn;
ASSERT( pagetable_val(ed->arch.monitor_table) );
* First get the mfn for hl2_table by looking at monitor_table
*/
hl2e = mpl2e[LINEAR_PT_VIRT_START >> L2_PAGETABLE_SHIFT];
- ASSERT(l2_pgentry_val(hl2e) & _PAGE_PRESENT);
- mfn = l2_pgentry_val(hl2e) >> PAGE_SHIFT;
- ASSERT(mfn);
+ if ( l2_pgentry_val(hl2e) & _PAGE_PRESENT )
+ {
+ mfn = l2_pgentry_val(hl2e) >> PAGE_SHIFT;
+ ASSERT(mfn);
+ put_shadow_ref(mfn);
+ }
+
+ sl2e = mpl2e[SH_LINEAR_PT_VIRT_START >> L2_PAGETABLE_SHIFT];
+ if ( l2_pgentry_val(sl2e) & _PAGE_PRESENT )
+ {
+ mfn = l2_pgentry_val(sl2e) >> PAGE_SHIFT;
+ ASSERT(mfn);
+ put_shadow_ref(mfn);
+ }
- put_shadow_ref(mfn);
unmap_domain_mem(mpl2e);
/*
*/
void vmx_shadow_clear_state(struct domain *d)
{
- SH_VVLOG("vmx_clear_shadow_state:");
+ SH_VVLOG("%s:", __func__);
shadow_lock(d);
free_shadow_pages(d);
shadow_unlock(d);
+ update_pagetables(d->exec_domain[0]);
}
unsigned long
BUG(); /* XXX Deal gracefully with failure. */
}
+ SH_VVLOG("shadow_hl2_table(gpfn=%p, gmfn=%p, smfn=%p) => %p",
+ gpfn, gmfn, smfn, hl2mfn);
perfc_incrc(shadow_hl2_table_count);
hl2 = map_domain_mem(hl2mfn << PAGE_SHIFT);
// How many outstanding writable PTEs for this page are there?
//
- write_refs = (frame_table[readonly_gmfn].u.inuse.type_info & PGT_count_mask);
- if ( write_refs && (frame_table[readonly_gmfn].u.inuse.type_info & PGT_pinned) )
+ write_refs =
+ (frame_table[readonly_gmfn].u.inuse.type_info & PGT_count_mask);
+ if ( write_refs &&
+ (frame_table[readonly_gmfn].u.inuse.type_info & PGT_pinned) )
+ {
write_refs--;
+ }
if ( write_refs == 0 )
{
return 1;
}
- // Before searching all the L1 page tables, check the typical culprit first.
+ // Before searching all the L1 page tables, check the typical culprit first
//
if ( (prediction = predict_writable_pte_page(d, readonly_gpfn)) )
{
}
}
- FSH_LOG("%s: looking for %d refs, found %d refs\n",
+ FSH_LOG("%s: looking for %d refs, found %d refs",
__func__, write_refs, found);
return 0;
{
perfc_incrc(unshadow_l2_count);
shadow_unpin(smfn);
+ if ( unlikely(shadow_mode_external(d)) )
+ {
+ unsigned long hl2mfn;
+
+ if ( (hl2mfn = __shadow_status(d, entry->gpfn, PGT_hl2_shadow)) &&
+ (frame_table[hl2mfn].u.inuse.type_info & PGT_pinned) )
+ shadow_unpin(hl2mfn);
+ }
}
}
* SHADOW MODE: none enable translate external
*
* 4KB things:
- * guest_vtable lin_l2 mapped per gpdt lin_l2 via hl2 mapped per gpdt
- * shadow_vtable n/a sh_lin_l2 sh_lin_l2 mapped per gpdt
- * hl2_vtable n/a n/a lin_hl2 via hl2 mapped per gpdt
+ * guest_vtable lin_l2 mapped per gl2 lin_l2 via hl2 mapped per gl2
+ * shadow_vtable n/a sh_lin_l2 sh_lin_l2 mapped per gl2
+ * hl2_vtable n/a n/a lin_hl2 via hl2 mapped per gl2
* monitor_vtable n/a n/a n/a mapped once
*
* 4MB things:
- * guest_linear lin via gpdt lin via gpdt lin via hl2 lin via hl2
- * shadow_linear n/a sh_lin via spdt sh_lin via spdt sh_lin via spdt
+ * guest_linear lin via gl2 lin via gl2 lin via hl2 lin via hl2
+ * shadow_linear n/a sh_lin via sl2 sh_lin via sl2 sh_lin via sl2
* monitor_linear n/a n/a n/a ???
* perdomain perdomain perdomain perdomain perdomain
* R/O M2P R/O M2P R/O M2P n/a n/a
{
if ( unlikely(!(hl2mfn = __shadow_status(d, gpfn, PGT_hl2_shadow))) )
hl2mfn = shadow_hl2_table(d, gpfn, gmfn, smfn);
- if ( !get_shadow_ref(hl2mfn) )
- BUG();
-
if ( ed->arch.hl2_vtable )
unmap_domain_mem(ed->arch.hl2_vtable);
ed->arch.hl2_vtable = map_domain_mem(hl2mfn << PAGE_SHIFT);
if ( max_mode == SHM_external )
{
l2_pgentry_t *mpl2e = ed->arch.monitor_vtable;
+ l2_pgentry_t old_hl2e = mpl2e[l2_table_offset(LINEAR_PT_VIRT_START)];
+ l2_pgentry_t old_sl2e = mpl2e[l2_table_offset(SH_LINEAR_PT_VIRT_START)];
ASSERT( shadow_mode_translate(d) );
- BUG(); // ref counts for hl2mfn and smfn need to be maintained!
-
+ if ( !get_shadow_ref(hl2mfn) )
+ BUG();
mpl2e[l2_table_offset(LINEAR_PT_VIRT_START)] =
mk_l2_pgentry((hl2mfn << PAGE_SHIFT) | __PAGE_HYPERVISOR);
+ if ( l2_pgentry_val(old_hl2e) & _PAGE_PRESENT )
+ put_shadow_ref(l2_pgentry_val(old_hl2e) >> PAGE_SHIFT);
+ if ( !get_shadow_ref(smfn) )
+ BUG();
mpl2e[l2_table_offset(SH_LINEAR_PT_VIRT_START)] =
mk_l2_pgentry((smfn << PAGE_SHIFT) | __PAGE_HYPERVISOR);
+ if ( l2_pgentry_val(old_sl2e) & _PAGE_PRESENT )
+ put_shadow_ref(l2_pgentry_val(old_sl2e) >> PAGE_SHIFT);
// XXX - maybe this can be optimized somewhat??
local_flush_tlb();
if ( !(smfn = __shadow_status(d, ptbase_pfn, PGT_base_page_table)) )
{
printk("%s-PT %p not shadowed\n", s, gptbase);
- errors++;
goto out;
}
if ( page_out_of_sync(pfn_to_page(ptbase_mfn)) )
static inline int
shadow_get_page_from_l1e(l1_pgentry_t l1e, struct domain *d)
{
- int res = get_page_from_l1e(l1e, d);
+ l1_pgentry_t nl1e = mk_l1_pgentry(l1_pgentry_val(l1e) & ~_PAGE_GLOBAL);
+ int res = get_page_from_l1e(nl1e, d);
unsigned long mfn;
struct domain *owner;
- ASSERT( l1_pgentry_val(l1e) & _PAGE_PRESENT );
+ ASSERT( l1_pgentry_val(nl1e) & _PAGE_PRESENT );
if ( unlikely(!res) && IS_PRIV(d) && !shadow_mode_translate(d) &&
- !(l1_pgentry_val(l1e) & L1_DISALLOW_MASK) &&
- (mfn = l1_pgentry_to_pfn(l1e)) &&
+ !(l1_pgentry_val(nl1e) & L1_DISALLOW_MASK) &&
+ (mfn = l1_pgentry_to_pfn(nl1e)) &&
pfn_is_ram(mfn) &&
- (owner = page_get_owner(pfn_to_page(l1_pgentry_to_pfn(l1e)))) &&
+ (owner = page_get_owner(pfn_to_page(l1_pgentry_to_pfn(nl1e)))) &&
(d != owner) )
{
- res = get_page_from_l1e(l1e, owner);
+ res = get_page_from_l1e(nl1e, owner);
printk("tried to map mfn %p from domain %d into shadow page tables "
"of domain %d; %s\n",
mfn, owner->id, d->id, res ? "success" : "failed");
if ( unlikely(!res) )
{
perfc_incrc(shadow_get_page_fail);
- FSH_LOG("%s failed to get ref l1e=%p\n", __func__, l1_pgentry_val(l1e));
+ FSH_LOG("%s failed to get ref l1e=%p", __func__, l1_pgentry_val(l1e));
}
return res;
/************************************************************************/
-//#define MFN3_TO_WATCH 0x8575
-#ifdef MFN3_TO_WATCH
-#define get_shadow_ref(__s) ( \
-{ \
- unsigned long _s = (__s); \
- if ( _s == MFN3_TO_WATCH ) \
- printk("get_shadow_ref(%x) oc=%d @ %s:%d in %s\n", \
- MFN3_TO_WATCH, frame_table[_s].count_info, \
- __FILE__, __LINE__, __func__); \
- _get_shadow_ref(_s); \
-})
-#define put_shadow_ref(__s) ( \
-{ \
- unsigned long _s = (__s); \
- if ( _s == MFN3_TO_WATCH ) \
- printk("put_shadow_ref(%x) oc=%d @ %s:%d in %s\n", \
- MFN3_TO_WATCH, frame_table[_s].count_info, \
- __FILE__, __LINE__, __func__); \
- _put_shadow_ref(_s); \
-})
-#else
-#define _get_shadow_ref get_shadow_ref
-#define _put_shadow_ref put_shadow_ref
-#endif
-
/*
* Add another shadow reference to smfn.
*/
static inline int
-_get_shadow_ref(unsigned long smfn)
+get_shadow_ref(unsigned long smfn)
{
u32 x, nx;
* Drop a shadow reference to smfn.
*/
static inline void
-_put_shadow_ref(unsigned long smfn)
+put_shadow_ref(unsigned long smfn)
{
u32 x, nx;
if ( unlikely(x == 0) )
{
- printk("put_shadow_ref underflow, oc=%p t=%p\n",
+ printk("put_shadow_ref underflow, smfn=%p oc=%p t=%p\n",
+ smfn,
frame_table[smfn].count_info,
frame_table[smfn].u.inuse.type_info);
BUG();
ASSERT( !(frame_table[smfn].u.inuse.type_info & PGT_pinned) );
frame_table[smfn].u.inuse.type_info |= PGT_pinned;
- if ( !get_shadow_ref(smfn) )
+ if ( unlikely(!get_shadow_ref(smfn)) )
BUG();
}
static inline void
shadow_unpin(unsigned long smfn)
{
+ ASSERT( (frame_table[smfn].u.inuse.type_info & PGT_pinned) );
+
frame_table[smfn].u.inuse.type_info &= ~PGT_pinned;
put_shadow_ref(smfn);
}
perfc_incrc(validate_pte_calls);
#if 0
- FSH_LOG("validate_pte(old=%p new=%p)\n", old_pte, new_pte);
+ FSH_LOG("validate_pte(old=%p new=%p)", old_pte, new_pte);
#endif
old_spte = *shadow_pte_p;
if ( unlikely(__get_user(gpte, (unsigned long *)
&linear_pg_table[gva >> PAGE_SHIFT])) )
{
- FSH_LOG("gva_to_gpte got a fault on gva=%p\n", gva);
+ FSH_LOG("gva_to_gpte got a fault on gva=%p", gva);
return 0;
}